package maquinavirtual;

import java.util.InputMismatchException;
import java.util.Scanner;

public class ConjuntoInstrucoes {

	public void ADD() {
		Number num1, num2;
		num1 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1];
		num2 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo];

		Number soma = num1.doubleValue() + num2.doubleValue();
		Object retorno;
		if (num1 instanceof Integer && num2 instanceof Integer) {
			retorno = soma.intValue();
		} else {
			retorno = soma.doubleValue();
		}

		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = retorno;
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void DII() {
		if ((int) MaquinaVirtual.pilha[MaquinaVirtual.topo] == 0) {
			System.err.println("RUNTIME error: divis�o por 0");
			return;
		}
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (int) ((int) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] / (int) MaquinaVirtual.pilha[MaquinaVirtual.topo]);
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void DIV() {
		if ((int) MaquinaVirtual.pilha[MaquinaVirtual.topo] == 0) {
			System.err.println("RUNTIME error: divis�o por 0");
			return;
		}

		Number num1, num2;
		num1 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1];
		num2 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo];

		Number div = num1.doubleValue() / num2.doubleValue();
		Object retorno;
		retorno = div.doubleValue();

		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = retorno;
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void MUL() {
		Number num1, num2;
		num1 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1];
		num2 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo];

		Number mul = num1.doubleValue() * num2.doubleValue();
		Object retorno;
		if (num1 instanceof Integer && num2 instanceof Integer) {
			retorno = mul.intValue();
		} else {
			retorno = mul.doubleValue();
		}

		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = retorno;
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;

	}

	public void SUB() {
		Number num1, num2;
		num1 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1];
		num2 = (Number) MaquinaVirtual.pilha[MaquinaVirtual.topo];

		Number soma = num1.doubleValue() + num2.doubleValue();
		Object retorno;
		if (num1 instanceof Integer && num2 instanceof Integer) {
			retorno = soma.intValue();
		} else {
			retorno = soma.doubleValue();
		}

		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = retorno;
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void ALB(int deslocamento) {
		for (int i = MaquinaVirtual.topo + 1; MaquinaVirtual.topo <= deslocamento; i++) {
			MaquinaVirtual.pilha[i] = false;
		}
		MaquinaVirtual.topo = MaquinaVirtual.topo + deslocamento;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void ALI(int deslocamento) {
		for (int i = MaquinaVirtual.topo + 1; i <= MaquinaVirtual.topo
				+ deslocamento; i++) {
			MaquinaVirtual.pilha[i] = 0;
		}
		MaquinaVirtual.topo = MaquinaVirtual.topo + deslocamento;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void ALR(int deslocamento) {
		for (int i = MaquinaVirtual.topo + 1; i <= MaquinaVirtual.topo
				+ deslocamento; i++) {
			MaquinaVirtual.pilha[i] = 0.0;
		}
		MaquinaVirtual.topo = MaquinaVirtual.topo + deslocamento;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void ALS(int deslocamento) {
		for (int i = MaquinaVirtual.topo + 1; i <=  MaquinaVirtual.topo 
				+ deslocamento; i++) {
			MaquinaVirtual.pilha[i] = "";
		}
		MaquinaVirtual.topo = MaquinaVirtual.topo + deslocamento;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void LDB(Object constante) {
		MaquinaVirtual.topo = MaquinaVirtual.topo + 1;
		MaquinaVirtual.pilha[MaquinaVirtual.topo] = (boolean) constante;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void LDI(Object constante) {
		int constInt = Integer.parseInt((String)constante);
		MaquinaVirtual.topo = MaquinaVirtual.topo + 1;
		MaquinaVirtual.pilha[MaquinaVirtual.topo] = (int) constInt;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void LDR(Object constante) {
		double constDouble = Double.parseDouble((String)constante);
		MaquinaVirtual.topo = MaquinaVirtual.topo + 1;
		MaquinaVirtual.pilha[MaquinaVirtual.topo] = (double) constDouble;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void LDS(Object constante) {
		MaquinaVirtual.topo = MaquinaVirtual.topo + 1;
		MaquinaVirtual.pilha[MaquinaVirtual.topo] = (String) constante;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void LDV(int endereco) {
		MaquinaVirtual.topo = MaquinaVirtual.topo + 1;
		MaquinaVirtual.pilha[MaquinaVirtual.topo] = MaquinaVirtual.pilha[endereco];
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void STR(int endereco) {
		MaquinaVirtual.pilha[endereco] = MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void AND() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (Boolean) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1]
				&& (Boolean) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void NOT() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo] = !(Boolean) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void OR() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (Boolean) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1]
				|| (Boolean) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void BGE() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (int) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] >= (int) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void BGR() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (int) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] > (int) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void DIF() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = !MaquinaVirtual.pilha[MaquinaVirtual.topo - 1]
				.equals(MaquinaVirtual.pilha[MaquinaVirtual.topo]);
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void EQL() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = MaquinaVirtual.pilha[MaquinaVirtual.topo - 1]
				.equals(MaquinaVirtual.pilha[MaquinaVirtual.topo]);
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void SME() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (int) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] <= (int) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void SMR() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (int) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] < (int) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void JMF(int endereco) {
		if ((Boolean) MaquinaVirtual.pilha[MaquinaVirtual.topo] == false) {
			MaquinaVirtual.ponteiro = endereco;
		} else {
			MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
		}
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
	}

	public void JMP(int endereco) {
		MaquinaVirtual.ponteiro = endereco;
	}

	public void JMT(int endereco) {
		if ((Boolean) MaquinaVirtual.pilha[MaquinaVirtual.topo] == true) {
			MaquinaVirtual.ponteiro = endereco;
		} else {
			MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
		}
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
	}

	public void STP() {
		MaquinaVirtual.exit = true;
	}

	public void REA(int tipo) {
		Scanner s = new Scanner(System.in);
		Object valor = null;
		MaquinaVirtual.topo = MaquinaVirtual.topo + 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
		try {
			switch (tipo) {
			case 1:
				valor = s.nextInt();
				break;
			case 2:
				valor = s.nextFloat();
				break;
			case 3:
				valor = s.next();
				break;
			case 4:
				valor = s.nextBoolean();
				break;
			}

		} catch (InputMismatchException e) {
			System.out.println("RUNTIME error");
			MaquinaVirtual.exit = true;
		}

		MaquinaVirtual.pilha[MaquinaVirtual.topo] = valor;
	}

	public void WRT() {
		System.out.print(">> " + MaquinaVirtual.pilha[MaquinaVirtual.topo] + "\n");
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void MOD() {
		if ((int) MaquinaVirtual.pilha[MaquinaVirtual.topo] == 0) {
			System.err.println("RUNTIME error: divis�o por 0");
			return;
		}
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (int) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1]
				% (int) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void POW() {
		MaquinaVirtual.pilha[MaquinaVirtual.topo - 1] = (int) MaquinaVirtual.pilha[MaquinaVirtual.topo - 1]
				^ (int) MaquinaVirtual.pilha[MaquinaVirtual.topo];
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}

	public void STC(int deslocamento){
		for(int i = MaquinaVirtual.topo - deslocamento; i <= MaquinaVirtual.topo - 1;i++ ){
			MaquinaVirtual.pilha[i] = MaquinaVirtual.pilha[MaquinaVirtual.topo];
		}
		MaquinaVirtual.topo = MaquinaVirtual.topo - 1;
		MaquinaVirtual.ponteiro = MaquinaVirtual.ponteiro + 1;
	}
	
}
